home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / util / libs / MMULib.lha / MMULib / Lib_Sources / mu_tableparse.asm < prev    next >
Encoding:
Assembly Source File  |  1998-10-04  |  27.9 KB  |  549 lines

  1. ;*************************************************************************
  2. ;** mmu.library                                                         **
  3. ;**                                                                     **
  4. ;** a system library for arbitration and control of the MC68K MMUs      **
  5. ;**                                                                     **
  6. ;** © 1998 THOR-Software, Thomas Richter                                **
  7. ;** No commercial use, reassembly, modification without prior, written  **
  8. ;** permission of the authors.                                          **
  9. ;** Including this library in any commercial software REQUIRES a        **
  10. ;** written permission and the payment of a small fee.                  **
  11. ;**                                                                     **
  12. ;** This is an internal header file, do not depend on anything here.    **
  13. ;** Use the official include files.                                     **
  14. ;** Distributed only for the mmu.library development group for private  **
  15. ;** use.                                                                **
  16. ;**                                                                     **
  17. ;**---------------------------------------------------------------------**
  18. ;** New Unified table scanner,  (NUTS) Version 0.00                     **
  19. ;**     © 1998  THOR-Software                                           **
  20. ;*************************************************************************
  21.  
  22. ;FOLD Includes
  23.         include inc:macros.asm
  24.         include inc:exec_lib.asm
  25.         include mu_lib.i
  26.         include mu_context.i
  27.         include mu_descriptor.i
  28.         include kaputstr.i
  29. ;ENDFOLD
  30. ;FOLD External References
  31.         xref LockContext
  32.         xref UnlockContext
  33.         xref MUAlert
  34.         xref FreePointerTable
  35.         xref DefineMapping
  36. ;ENDFOLD
  37. ;FOLD Defines
  38. ;ENDFOLD
  39.  
  40.         section main_code,code
  41.         machine mc68020
  42.  
  43. ;FOLD ParseMMUTable
  44. ;*************************************************
  45. ;** ParseMMUTable                               **
  46. ;** parse the MMU table given by the config     **
  47. ;** *a1, to the Context *a0                     **
  48. ;** d0=TRUE: worked fine                        **
  49. ;*************************************************
  50.         xdef ParseMMUTable
  51. ParseMMUTable:
  52.         saveregs d2/d4/a5
  53.         defvar
  54.          auto.b pmt_descriptor,atd_len
  55.         endvar
  56.  
  57.         move.l a0,a5                    ;keep the context in a5
  58.         bsr LockContext
  59.  
  60.         move.l a7,a0
  61.         jsr mulib_RootStarter(a6)       ;get the root descriptor
  62.         move.l d0,d2                    ;an error ?
  63.         beq.s .errorexit
  64.         bpl.s .disabled                 ;it's just disabled!
  65.  
  66.         move.l atd_Pointer(a7),a1       ;read this pointer
  67.         move.l a7,a0                    ;fill in this type
  68.         move.b atd_NextType(a7),d0      ;type of the descriptor to be read
  69.         moveq #0,d1                     ;masking is levelA
  70.         jsr mulib_ReadDescriptor(a6)    ;read it
  71.  
  72.         sub.l a1,a1                     ;address to be scanned: 0
  73.         move.l a7,a0                    ;table descriptor of this level
  74.         moveq #0,d0                     ;current level
  75.         bsr.s RecursiveScan             ;and now, scan it
  76.         bne.s .disabled                 ;worked? return TRUE
  77.  
  78.         moveq #0,d2
  79.         bra.s .errorexit
  80.  
  81. .disabled:
  82.         moveq #-1,d2                    ;don't scan the table, just use the prepared stuff
  83. .errorexit:
  84.         move.l a5,a0
  85.         bsr UnlockContext
  86.         move.l d2,d0
  87.  
  88.         freevar
  89.         loadregs
  90.         rts
  91. ;ENDFOLD
  92. ;FOLD RecursiveScan
  93. ;*************************************************
  94. ;** RecursiveScan                               **
  95. ;** Scan the abstract descriptor at *a0         **
  96. ;** recursively                                 **
  97. ;** it describes address base a1 at level d0    **
  98. ;** (d0=-1 is root level, i.e. the descriptor   **
  99. ;** points effectively to the user root pointer **
  100. ;** in the MMU configuration)                   **
  101. ;** *a5 is the context (already locked)         **
  102. ;**                                             **
  103. ;** returns 0 in case of failure                **
  104. ;** returns 2 if this level of the tree         **
  105. ;** consists purely of one type of properties   **
  106. ;** so we may take a shortcut if we find a      **
  107. ;** descriptor pointing to the same branch      **
  108. ;** of the tree                                 **
  109. ;** in this case, properties and data are       **
  110. ;** filled into d1 and a0                       **
  111. ;** returns 1 if no shortcut possible           **
  112. ;*************************************************
  113. RecursiveScan:
  114.         saveregs d2-d7/a2-a4
  115.         defvar
  116.          auto.b rcs_descriptor,atd_len
  117.          auto.l rcs_increment                           ;from one to the next descriptor of the table
  118.          auto.l rcs_entries                             ;#of entries on that level of the table
  119.          auto.l rcs_lastproperties
  120.          auto.l rcs_lastpointer
  121.          auto.l rcs_lastbase
  122.          auto.b rcs_continuous
  123.          auto.b rcs_tableshift
  124.          auto.w rcs_nextlevel
  125.          auto.w rcs_lastindex
  126.          auto.b rcs_lasttableshift
  127.          auto.b rcs_thistype                            ;backup of atd_thistype
  128.         endvar
  129.  
  130.         kaputstr "{"
  131.  
  132.         move.l a0,a2                                    ;keep atd
  133.         move.l d0,d4                                    ;keep level
  134.         move.l a1,a4                                    ;keep base address
  135.         addq.w #1,d0                                    ;next level
  136.         tst.b ctx_LevelABits(a5,d0.w)                   ;is there a next level ?
  137.         bne.s .gotnext
  138.         moveq #4,d0                                     ;at page level
  139. .gotnext:
  140.         clr.l rcs_lastpointer(a7)
  141.         move.w d0,rcs_nextlevel(a7)
  142.         move.l #(1<<mapp_invalid),rcs_lastproperties(a7)
  143.  
  144.         st.b rcs_continuous(a7)                         ;mapping is continous
  145.         move.l ctx_LevelATableSz(a5,d4.w*4),d3          ;lower limit greater than table size ?
  146.         moveq #0,d7
  147.         move.b ctx_LevelAPos(a5,d4.w),d5                ;bit position in the address of this level
  148.         subq.l #1,d3
  149.         add.b ctx_LevelABits(a5,d4.w),d5                ;position of the LSB instead of MSB
  150.         moveq #0,d0
  151.         move.b d5,rcs_tableshift(a7)
  152.  
  153.         move.w atd_LowerLimit(a2),d0                    ;do we have a lower limit ?
  154.         beq.s .nolowerlimit
  155.                                                         ;yup!
  156.         clr.b rcs_continuous(a7)                        ;mapping is no longer continous
  157.         moveq #0,d5                                     ;lower
  158.         move.l d0,d6                                    ;upper: up to here no access
  159.         moveq #0,d1                                     ;no user data
  160.         cmp.l d3,d6                                     ;is the upper level useful ?
  161.         bls.s .nocut
  162.         move.l d3,d6                                    ;but not more than all descriptors at this level
  163. .nocut:
  164.         move.l #(1<<mapp_invalid),d0                    ;type is invalid
  165.         bsr _SetPageRange                               ;mark this range as invalid
  166.         beq .exit                                       ;on error exit
  167. .nolowerlimit:
  168.         moveq #0,d7
  169.         moveq #0,d6
  170.         move.w atd_UpperLimit(a2),d7                    ;get upper limit
  171.         move.w atd_LowerLimit(a2),d6                    ;and lower
  172.         cmp.l d3,d7                                     ;must not be greater than that!
  173.         bls.s .nocuthigher
  174.         move.l d3,d7                                    ;restrict to this value
  175. .nocuthigher:
  176.         move.l a2,a0
  177.         move.w d6,d0
  178.         jsr mulib_ReadIncrement(a6)                     ;get increment and pointer
  179.         movem.l d0/d3,rcs_increment(a7)                 ;keep increment,# entries
  180.         move.l a0,a3                                    ;Pointer -> a3
  181.  
  182.         kaputstr <"index range %lx to %lx">,d6,d7
  183.  
  184.         do
  185.          cmp.w d7,d6                                    ;are we out of range ?
  186.          break hi                                       ;abort, if so. Range is inclusive
  187.  
  188.          kaputstr <"index processed %lx">,d6
  189.  
  190.          move.l a7,a0
  191.          move.l a3,a1
  192.          move.b atd_NextType(a2),d0                     ;type
  193.          move.w rcs_nextlevel(a7),d1                    ;level
  194.          move.b d0,rcs_ThisType(a7)                     ;keep me
  195.          jsr mulib_ReadDescriptor(a6)                   ;read the descriptor
  196.  
  197.  
  198.          move.l atd_Properties(a2),d1
  199.  
  200.          kaputstr <"descriptor (%08lx), properties %08lx">,(a3),d1
  201.  
  202.          move.b atd_ThisType(a7),d0                     ;get type of this one
  203.          or.l d1,atd_Properties(a7)                     ;collect property flags
  204.          and.b #3,d0                                    ;ignore size
  205.          cmp.b #atdt_indirect,d0                        ;is this propably indirect ?
  206.          bne.s .noindirect
  207.                                                         ;if so, increase the level temporarely and
  208.                                                         ;reference the indirect pointer
  209.          move.l a7,a0
  210.          move.l atd_Pointer(a7),a1
  211.  
  212.          kaputstr <"indirect descriptor (%08lx)">,(a1)
  213.  
  214.          moveq #5,d1                                    ;level is indirection
  215.          move.b atd_NextType(a7),d0                     ;type of this descriptor
  216.          jsr mulib_ReadDescriptor(a6)                   ;double indirection is not allowed and
  217.          move.b rcs_ThisType(a7),d1                     ;get type again
  218.                                                         ;hopefully regarded as invalid by ReadDescriptor
  219.          move.b atd_ThisType(a7),d0                     ;read type again
  220.          and.b #$fc,d1
  221.          and.b #3,d0
  222.          or.b #atdt_indirect,d1                         ;mark this as indirect
  223.          move.b d1,rcs_ThisType(a7)
  224. .noindirect:
  225.          tst.b d0
  226.          beq .invalid                                   ;invalid ?
  227.          cmp.b #atdt_table,d0                           ;is this propably a page descriptor ?
  228.          beq .table
  229. .page:                                                  ;here: we got a page descriptor
  230.                                                         ;check now, how many page descriptors of
  231.                                                         ;the same type follow in sequence.
  232.                                                         ;two things could happen:
  233.                                                         ;a) a continous mapping of logical
  234.                                                         ;addresses to physical.
  235.                                                         ;this means specifically that we
  236.                                                         ;need to add an offset to each compare
  237.                                                         ;b) a "bundled" mapping of logical
  238.                                                         ;addresses to all the same physical
  239.                                                         ;page. This might be done by certain
  240.                                                         ;system software to map out
  241.                                                         ;complete pages without creating a
  242.                                                         ;bus error on access and is similar to
  243.                                                         ;what this library does on "tolerated"
  244.                                                         ;pages.
  245.  
  246.                                                         ;first, we handle early page
  247.                                                         ;descriptors with limits
  248.          move.w rcs_nextlevel(a7),d0
  249.          cmp.w #4,d0                                    ;page level descriptors never carry limits
  250.          bge .nolimit
  251.          move.l ctx_LevelATableSz(a5,d0.w*4),d3         ;required to bound the limits
  252.          movem.w atd_LowerLimit(a7),d0-d1               ;get lower and upper limit
  253.          subq.l #1,d3
  254.          cmp.w d3,d0
  255.          bls.s .nocutlower2
  256.          move.l d3,d0
  257. .nocutlower2:
  258.          cmp.w d3,d1
  259.          bls.s .nocuthigher2
  260.          move.l d3,d1
  261. .nocuthigher2:
  262.          tst.w d0                                       ;do we have a lower limit ?
  263.          bne.s .withlimit
  264.          cmp.w d3,d1                                    ;do we have a higher limit ?
  265.          beq .nolimit
  266. .withlimit:
  267.  
  268.                                                         ;here: we got a limit
  269.          ;clr.b rcs_continuous(a7)                      ;this is never continous
  270.                                                         ;will be cleared below
  271.          move.l a4,rcs_lastbase(a7)
  272.          move.b rcs_tableshift(a7),d2
  273.          move.l d6,d5
  274.          move.b d2,rcs_lasttableshift(a7)
  275.          movem.w d0-d1,atd_LowerLimit(a7)               ;keep limits
  276.          ror.l d2,d5                                    ;shift delta in place
  277.          move.w rcs_nextlevel(a7),d1
  278.          adda.l d5,a4                                   ;new base address
  279.          add.b ctx_LevelABits(a5,d1.w),d2               ;increment tableshift
  280.          move.w d6,rcs_lastindex(a7)                    ;save this guy, too
  281.          move.b d2,rcs_tableshift(a7)                   ;saveback tableshift for stack magic
  282.  
  283.          tst.w d0                                       ;do we have a lower limit ?
  284.          beq.s .nolowerpagelimit
  285.          moveq #0,d5                                    ;if so, disable this to
  286.          move.l d0,d6                                   ;to this
  287.          move.l #(1<<mapp_invalid),d0
  288.          moveq #0,d1
  289.          bsr _SetPageRange
  290.          beq .exit
  291. .nolowerpagelimit:
  292.          movem.w atd_LowerLimit(a7),d5-d6               ;restore limits
  293.          cmp.l d6,d5                                    ;is something left ?
  294.          bhi.s .nocontents
  295.          move.l atd_Pointer(a7),d1                      ;get page pointer
  296.          move.l atd_Properties(a7),d0                   ;get properties
  297.          addq.l #1,d6
  298.          sub.l a4,d1                                    ;do we have a delta ?
  299.          beq.s .nodeltapage
  300.          bset #mapp_remapped,d0                         ;if so, enable remapped
  301. .nodeltapage:
  302.          bsr _SetPageRange
  303.          beq .exit
  304.          subq.l #1,d6
  305. .nocontents:
  306.          cmp.l d3,d6                                    ;do we have an upper limit ?
  307.          beq.s .noupperpagelimit
  308.          move.l d6,d5
  309.          move.l #(1<<mapp_invalid),d0                   ;is invalid
  310.          move.l d3,d6                                   ;from here to there
  311.          addq.l #1,d5
  312.          addq.l #1,d6
  313.          moveq #0,d1                                    ;no user data
  314.          bsr _SetPageRange
  315.          beq .exit
  316. .noupperpagelimit:
  317.          moveq #0,d6
  318.          move.b rcs_lasttableshift(a7),rcs_tableshift(a7)       ;restore tableshift
  319.          move.w rcs_lastindex(a7),d6                    ;restore index from above
  320.          move.l rcs_lastbase(a7),a4                     ;restore base pointer
  321.          addq.w #1,d6                                   ;next entry
  322.          bra .nexttable                                 ;this clears rcs_continous to
  323.  
  324. .nolimit:
  325.          move.l d6,d5                                   ;keep initial entry
  326.          move.l a3,a0
  327.          move.l rcs_increment(a7),d2                    ;get increment
  328.          cmp.w d7,d5                                    ;compare with the maximum. No need to bundle if this is the last one
  329.          beq.s .lastpage
  330.          lea (a3,d2.l),a1                               ;get the next one
  331.                                                         ;obviously, the same page descriptor is
  332.                                                         ;identical to itself, so we have to scan the next
  333.          moveq #0,d1                                    ;no offset
  334.          move.b rcs_ThisType(a7),d0                     ;and type of this guy
  335.          jsr mulib_CmpDescriptor(a6)                    ;are these the same ?
  336.          beq.s .bundled                                 ;if so, these are declared as "bundled"
  337.                                                         ;they map all to the same phyical address
  338. .lastpage:                                              ;only one page, then remapped, not bundled
  339.                                                         ;here: unbundled, we need to add an offset
  340.          move.l a3,a1                                   ;start over
  341.          move.l ctx_LevelASize(a5,d4.w*4),d3            ;get increment, i.e. the range of logical addresses this
  342.                                                         ;descriptor covers
  343.          moveq #0,d2                                    ;clear initial increment
  344.          do
  345.           cmp.w d7,d6                                   ;are we done with that table completely ?
  346.           bhi.s .donepage
  347.           move.l d2,d1                                  ;this delta
  348.           move.b rcs_ThisType(a7),d0                    ;type of the descriptor we're pointing to
  349.           move.l a1,a3                                  ;keep pointer for later
  350.           jsr mulib_CmpDescriptor(a6)                   ;compare if the two descriptors are equal
  351.           break.s ne                                    ;abort if not
  352.           add.l d3,d2                                   ;add the size of a early termination page at this level
  353.           addq.w #1,d6                                  ;continue with the next entry
  354.          loop.s
  355. .donepage:
  356.          clr.b rcs_continuous(a7)                       ;pages can never be shortcutted
  357.          move.l d5,d0
  358.          move.b rcs_tableshift(a7),d1
  359.          ror.l d1,d0
  360.          move.l atd_Pointer(a7),d1                      ;data is page address
  361.          lea (a4,d0.l),a0
  362.          move.l atd_Properties(a7),d0                   ;get properties
  363.          sub.l a0,d1                                    ;do we map this to the physical page ?
  364.          beq.s .noremap
  365.          bset #mapp_remapped,d0                         ;this page is mapped to somewhere else
  366. .noremap:
  367.          bsr _SetPageRange
  368.          beq .exit
  369.          reloop
  370.  
  371.  
  372. .bundled:                                               ;now again the same sport:
  373.                                                         ;find as many bundled addresses as possible
  374.          move.l a3,a1                                   ;start over from here. At least ONE will be the result
  375.          do
  376.           cmp.w d7,d6                                   ;are we done with that table completely ?
  377.           bhi.s .donebundled
  378.           moveq #0,d1                                   ;no deltas. These MUST be literally the same
  379.           move.b rcs_ThisType(a7),d0                    ;type of the descriptor we're pointing to
  380.           move.l a1,a3                                  ;keep pointer for later
  381.           jsr mulib_CmpDescriptor(a6)                   ;compare if the two descriptors are equal
  382.           break.s ne                                    ;abort if not
  383.           addq.w #1,d6                                  ;continue with the next entry
  384.          loop.s
  385.                                                         ;here: abort before the table went out of data
  386.          clr.b rcs_continuous(a7)                       ;nope, this table is clearly not continous of one type
  387. .donebundled:                                           ;we're done. Found [d5,d6] bundled entries
  388.          move.l atd_Properties(a7),d0                   ;get properties
  389.          move.l atd_Pointer(a7),d1                      ;data is page address
  390.          bset #mapp_bundled,d0                          ;adjust the properties of this guy
  391.          bsr _SetPageRange
  392.          beq .exit
  393.          reloop
  394.  
  395. .invalid:                                               ;here: found an invalid descriptor
  396.                                                         ;check, how many invalid descriptors follow
  397.          move.l d6,d5                                   ;and setup a complete range of them
  398.          move.l a3,a0                                   ;get the descriptor again
  399.          move.l a3,a1                                   ;and again
  400.          do
  401.           cmp.w d7,d6                                   ;are we done with that table completely ?
  402.           bhi.s .doneinvalid
  403.           moveq #0,d1                                   ;no deltas. These MUST be literally the same
  404.           move.b rcs_ThisType(a7),d0                    ;type of the descriptor we're pointing to
  405.           move.l a1,a3                                  ;keep pointer for later
  406.           jsr mulib_CmpDescriptor(a6)                   ;compare if the two descriptors are equal
  407.           break.s ne                                    ;abort if not
  408.           addq.w #1,d6                                  ;continue with the next entry
  409.          loop.s
  410.                                                         ;here: abort before the table went out of data
  411.          clr.b rcs_continuous(a7)                       ;nope, this table is clearly not continous of one type
  412. .doneinvalid:
  413.                                                         ;here: found the properties of
  414.                                                         ;the entries [d5,d6]
  415.          move.l #(1<<mapp_invalid),d0                   ;properties are invalid
  416.          moveq #0,d1                                    ;no user data
  417.          bsr _SetPageRange
  418.          beq .exit                                      ;leave if this does not work
  419.          reloop                                         ;and continue in all other cases.
  420.  
  421. .table:                                                 ;we got a table descriptor here
  422.                                                         ;this is a bit more complex
  423.                                                         ;first thing is that we scan this
  424.                                                         ;one recursively with ourselves
  425.          move.l d6,d0                                   ;calculate address base
  426.          move.l a7,a0                                   ;using this abstract descriptor
  427.          move.b rcs_tableshift(a7),d1
  428.          ror.l d1,d0                                    ;calculate the logical address here
  429.          lea (a4,d0.l),a1                               ;here we go
  430.          move.w rcs_nextlevel(a7),d0                    ;at the next level
  431.          bsr RecursiveScan                              ;and call ourselves! Yoho!
  432.                                                         ;this can't become an infinite
  433.                                                         ;recursion because sooner or later
  434.                                                         ;we arrive at the bottom = page level of the
  435.                                                         ;tree and the ReadDescriptor function
  436.                                                         ;does then no longer generate "table" type entries
  437.          beq .exit                                      ;leave on exit
  438.          addq.w #1,d6                                   ;and now the next level
  439.                                                         ;the current descriptor was processed inside
  440.                                                         ;we check now, if the next one looks identically
  441.          cmp.b #2,d0                                    ;was this a continuous branch of the tree?
  442.          bne.s .nexttable                               ;if not, then we can't shortcut it and have to continue
  443.                                                         ;the ordinary way
  444.          cmp.w d7,d6                                    ;if we're done, we're done
  445.          break.s hi
  446.  
  447.          movem.l d1/a0,rcs_lastproperties(a7)           ;restore Properties/Pointer from level below
  448.  
  449.                                                         ;o.k., now take the shortcut
  450.          move.l a3,a0                                   ;from here
  451.          move.l rcs_increment(a7),d0
  452.          move.l d6,d5                                   ;start at this entry, which is the entry behind ours
  453.          lea (a3,d0.l),a1                               ;the next one to compare
  454.          do
  455.           cmp.w d7,d6
  456.           bhi.s .donetable
  457.           moveq #0,d1                                   ;no deltas. These MUST be literally the same
  458.           move.b rcs_ThisType(a7),d0                    ;type of the descriptor we're pointing to
  459.           move.l a1,a3
  460.           jsr mulib_CmpDescriptor(a6)                   ;compare if the two descriptors are equal
  461.           break.s ne                                    ;abort if not
  462.           addq.w #1,d6                                  ;continue with the next entry
  463.          loop.s
  464.                                                         ;here: abort before the table went out of data
  465.          clr.b rcs_continuous(a7)                       ;nope, this table is clearly not continous of one type
  466. .donetable:                                             ;we're done. Found [d5,d6] table entries of the same type already collected
  467.          cmp.w d5,d6
  468.          reloop eq                                      ;continue, if nothing equal found
  469.          movem.l rcs_lastproperties(a7),d0-d1           ;this user data
  470.                                                         ;these properties, filled in by the level below
  471.          bsr _SetPageRange
  472.          beq.s .exit
  473.          reloop
  474.  
  475. .nexttable:
  476.          move.l rcs_increment(a7),d0
  477.          adda.l d0,a3                                   ;next pointer
  478.          clr.b rcs_continuous(a7)                       ;since the level below isn't continous, so are we.
  479.         loop
  480.  
  481.  
  482.                                                         ;we're done. What's left is to map out
  483.                                                         ;the upper limit as illegal
  484.         cmp.l rcs_entries(a7),d7                        ;is there a useable upper limit ?
  485.         beq.s .exitfine                                 ;if not, nothing to map out
  486.  
  487.         clr.b rcs_continuous(a7)                        ;mapping is no longer continous
  488.         move.l d7,d5                                    ;from here
  489.         move.l rcs_entries(a7),d6                       ;to here
  490.         addq.l #1,d5
  491.         moveq #0,d1                                     ;no user data
  492.         addq.l #1,d6
  493.         move.l #(1<<mapp_invalid),d0                    ;clearly invalid
  494.         bsr.s _SetPageRange
  495.         beq.s .exit
  496. .exitfine:
  497.         movem.l rcs_lastproperties(a7),d1/a0
  498.         moveq #2,d0                                     ;default is continuous
  499.                                                         ;the level on top is informed about
  500.                                                         ;the user data and properties of
  501.                                                         ;this level because that
  502.                                                         ;gets filled in by
  503.                                                         ;the SetPageRange below
  504.         kaputstr "}"
  505.         tst.b rcs_continuous(a7)                        ;is it?
  506.         bne.s .exit
  507.         subq.l #1,d0                                    ;harder work for the next level
  508. .exit:
  509.         freevar
  510.         loadregs
  511.         rts
  512.  
  513. ;** SetPageRange
  514. ;** set pages [d5..d6] to properties given in d0, UData in d1
  515. _SetPageRange:
  516.         saveregs d2/d5-d6
  517.         defvar
  518.          auto.b spr_map,map_len
  519.         endvar
  520.  
  521. spr_stack       =       map_len+3*4+4                   ;stack offset to stackframe above
  522.  
  523.         move.b spr_stack+rcs_tableshift(a7),d2          ;get tableshift
  524.         ror.l d2,d6                                     ;shift entry # to correct bit position
  525.         ror.l d2,d5
  526.         and.b #$fe,d6                                   ;in exceptional cases, one bit may leak thru
  527.         lea (a4,d5.l),a0                                ;higher
  528.         lea (a4,d6.l),a1                                ;lower
  529.  
  530.         movem.l d0-d1,map_properties(a7)
  531.         subq.l #1,a1
  532.         movem.l d0-d1,spr_stack+rcs_lastproperties(a7)
  533.         movem.l a0-a1,map_lower(a7)             ;upper, lower
  534.  
  535.         kaputstr <"[%08lx,%08lx) to %08lx, delta %08lx">,a0,a1,d0,d1
  536.  
  537.         moveq #-1,d0
  538.         clr.l map_flags(a7)
  539.         move.l d0,map_mask(a7)                  ;mask in everything
  540.         move.l a5,a0
  541.         move.l a7,a1
  542.         bsr DefineMapping
  543.  
  544.         freevar
  545.         loadregs
  546.         rts
  547. ;ENDFOLD
  548. ;
  549.